package com.py.framework.common.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.py.framework.common.UserCacheHelper;
import com.py.framework.core.filter.SecurityCheckFilter;
import com.py.framework.core.helper.HttpServletHelper;
import com.py.framework.core.rest.support.RestServiceResult;
import com.py.framework.core.utils.SerializingUtil;

/**
 * Token鉴权过滤器
 * @author Leegern
 * @date   2018年4月17日
 */
public class SecurityFilter implements Filter {
	
	/** 白名单列表 **/
	private Map<String, String> whiteMap;
	
	/*
	 * (non-Javadoc)
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;  
        HttpServletResponse response = (HttpServletResponse) res;  
        String servletPath = request.getServletPath();
        String jdResource = request.getHeader(SecurityCheckFilter.JD_RESOURCE);
        
        if (StringUtils.isBlank(servletPath)) {
        	String reqUri  = request.getRequestURI();
            String ctxPath = request.getContextPath();
        	servletPath    = reqUri.replaceFirst(ctxPath, "");
        }
        
        // 白名单之外的请求都要鉴权
        if (null == this.whiteMap || ! this.hasAuthAccess(servletPath)) {
        	/*
             * 首先从cookie中查找令牌, 如果不存在, 再从请求头中查找.
             */
            String jdToken = HttpServletHelper.getUserToken(request);
            
            // 是否为有效用户
            if (StringUtils.isBlank(jdToken) || ! UserCacheHelper.isValidUser(SerializingUtil.serialize(jdToken))) {
            	// 输出响应信息
            	this.printMsg(response, RestServiceResult.CODE_LOGOUT);
            	return;
            } 
            // 是否有资源访问权限
            if (StringUtils.isNotBlank(jdResource) && ! UserCacheHelper.hasValidResource(jdToken, jdResource)) {
            	// 输出响应信息
            	this.printMsg(response, RestServiceResult.CODE_NOAUTH);
            	return;
            }
        }
        chain.doFilter(req, res);
	}
	
	/*
	 * (non-Javadoc)
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	@Override
	public void init(FilterConfig config) throws ServletException {
		String whiteStr = config.getInitParameter("whiteList");
		if (StringUtils.isNotBlank(whiteStr)) {
			this.whiteMap = new HashMap<String, String>();
			String[] whiteList = whiteStr.split(",");
			for (String item : whiteList) {
				if (StringUtils.isNotBlank(item)) {
					this.whiteMap.put(item.trim(), item.trim());
				}
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see javax.servlet.Filter#destroy()
	 */
	@Override
	public void destroy() {

	}
	
	/**
	 * 判断资源是否有权限访问
	 * @param resource 资源地址
	 * @return
	 */
	private boolean hasAuthAccess(String resource) {
		boolean flag = false;
		String key = "";
		if (this.whiteMap.containsKey(resource)) {
			flag = true;
		} else {
			for (Map.Entry<String, String> entry : this.whiteMap.entrySet()) {
				key = entry.getKey();
				if (key.endsWith("/*")) {
					key = key.substring(0, (key.length() - 1));
					if (resource.startsWith(key)) {
						flag = true;
						break;
					}
				}
			}
		}
		return flag;
	}
	
	/**
	 * 输出文本
	 * @param response  
	 * @param code     状态码
	 * @throws IOException 
	 */
	private void printMsg(HttpServletResponse response, int code) throws IOException {
		// 设置格式为text/json
		response.setContentType("text/json");
		// 设置字符集为'UTF-8'
		response.setCharacterEncoding("UTF-8");
		
		// 设置返回信息
		RestServiceResult<String> result = new RestServiceResult<String>();
		result.setCode(code);
		if (RestServiceResult.CODE_LOGOUT == code) {
			result.setMsg("未登录！");
		} else {
			result.setMsg("无权限访问资源！");
		}
    	
		PrintWriter out = response.getWriter();
    	out.println(JSON.toJSONString(result));
    	out.flush();
    	out.close();
	}
}